function isObject(obj) {
  return typeof obj === 'object' && obj != null;
}

function cloneDeep(source) {
  if (typeof source === 'function') {
    let fn = source.bind(null);
    fn.prototype = cloneDeep(source.prototype);
    return fn;
  }
  if (source instanceof Date) {
    const date = new Date();
    date.setTime(source.getTime());
    return date;
  }
  if (source instanceof RegExp) {
    const Constructor = source.Constructor;
    return new Constructor(source);
  }
  if (!isObject(source)) return source; // 非对象返回自身
  // 解决循环引用
  const cache = new Map();
  const cacheTarget = cache.get(source);

  if (cacheTarget) {
    return cacheTarget;
  }

  var target = Array.isArray(source) ? [] : {};

  cache.set(source, target); // 解决循环引用

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (isObject(source[key])) {
        target[key] = cloneDeep(source[key]); // 注意这里
      } else {
        target[key] = source[key];
      }
    }
  }
  return target;
}

let a = {
  age: undefined,
  sex: Symbol('male'),
  jobs: function () { },
  name: 'hzzly'
}

console.log(cloneDeep(a))


function getFileList(obj, str = '', arr = []) {
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      if (typeof obj[key] === 'object' && obj[key] !== null) {
        const newStr = str + `/${key}`;
        getFileList(obj[key], newStr, arr)
      } else if (typeof obj[key] === 'boolean') {
        arr.push(str + `/${key}`);
      }
    }
  }
  return arr;
}

const files = {
  'a': {
    'b': {
      'c': {
        'd': {
          'e': true,
          'f': true
        },
        'g': true
      }
    }
  }
}
// getFileList(files) # => ['a/b/c/d/e', 'a/b/c/d/f', 'a/b/c/g']

console.log(getFileList(files))